package org.skyeye.modeling.api;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.skyeye.modeling.config.AppConstant;
import org.skyeye.modeling.model.Attribute;
import org.skyeye.modeling.model.MBase;
import org.skyeye.modeling.model.MConnection;
import org.skyeye.modeling.model.MDevice;
import org.skyeye.modeling.model.MLinker;
import org.skyeye.modeling.model.MNode;
import org.skyeye.modeling.model.MRoot;
import org.skyeye.modeling.model.MSOC;
import org.skyeye.modeling.model.MemorySpaceAttr;
import org.skyeye.modeling.vo.RootVO;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

public class OutputInfo {

	private static Map<String,MBase> cache = null;
	private static List<Conn> connQueue = null;
	public static boolean exportJson(String path, MRoot root) {
		System.out.println("root is null? "+(root==null));
		RootVO rootVO = new RootVO(root);		
		try {
			FileUtil.writeFileContent(path, rootVO.toJson());
		} catch (IOException e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}

	public static MRoot importJson(String path) throws Exception {
		String jsonStr = FileUtil.readFileByLines(path);
		System.out.println(jsonStr);
		
		JSONObject obj = JSONObject.parseObject(jsonStr);
		MRoot root = new MRoot();
		cache = new HashMap<String,MBase>();
		connQueue = new ArrayList<Conn>();
		parseJSON(obj,root,root);
		

//		MRoot root = new MRoot();
//		MSOC soc = new MSOC();
//		soc.setLocation(new Point(10,10));
//		soc.setName("soc_1");
//		MDevice device = new MDevice();
//		device.setLocation(new Point(30,30));
//		device.setName("device_1");
//		soc.addChild(device);
//		root.addChild(soc);
		return root;
	}
	
	public static void buildConnection() throws Exception {
		for(Conn conn : connQueue){
			MNode source = (MNode) cache.get(conn.source);
			MNode sink = (MNode) cache.get(conn.sink);
			if(source==sink){
				continue;
			}
			if(source==null||sink==null){
				throw new Exception("can't find device");
			}
			MConnection mconn = new MConnection(source, sink);
			if(null!=conn.length&&!conn.length.equals("")){
				mconn.setLength(conn.length);
			}
			if(null!=conn.startAddress&&!conn.startAddress.equals("")){
				mconn.setStartAddress(conn.startAddress);
			}
			source.connectOnAllInterface(mconn);
			sink.connectOnAllInterface(mconn);
//			source.addOutput(mconn);
//			sink.addInput(mconn);
			System.out.println("connect "+conn.source+"--"+conn.sink);
		}
	}

	public static void parseJSON(JSONObject obj,MRoot root,MBase parent){
		Point pos;
		Point start;
		Dimension size;
		int maxY = 0;
		if(parent instanceof MRoot){
			pos = new Point(10,10);
			start = new Point(10,10);
			size = new Dimension(1300, 5000);
		}else{
			MNode node = (MNode) parent;
			pos = new Point(30,30);
			start = new Point(30,30);
			size = node.getSize();
		}
		for(Entry<String,Object> entry: obj.entrySet()){
			
			String name = entry.getKey();
			Object value = entry.getValue();
			
			if (value instanceof JSONObject){
				JSONObject json = (JSONObject) value;
				String base = json.getString("base");
				String clas = json.getString("class");
				if(base.equals("soc")){
					MSOC soc = new MSOC();
					soc.setName(name);
					soc.setClassName(clas);
					soc.setBaseType(base);
					soc.setBaseName(adjustDeviceName(root,name));
					if(pos.x+AppConstant.DEFAULT_SOC_WIDTH>start.x+size.width-20){
						pos.x=start.x;
						pos.y = maxY+100;
					}
					soc.setLocation(new Point(pos.x,pos.y));
					pos.x=pos.x+AppConstant.DEFAULT_SOC_WIDTH+100;
					if(maxY<pos.y+AppConstant.DEFAULT_SOC_HEIGHT){
						maxY = pos.y+AppConstant.DEFAULT_SOC_HEIGHT;
					}
					System.out.println("new soc "+name);
					parent.addChild(soc);
					cache.put(name, soc);
					parseJSON(json,root, soc);
				}else if(base.equals("cpu") || base.equals("device")){
					MDevice device = new MDevice();
					device.setName(name);
					device.setClassName(clas);
					device.setBaseType(base);
					device.setBaseName(adjustDeviceName(root,name));
					if(pos.x+AppConstant.DEFAULT_DEVICE_NAME_WIDTH>start.x+size.width-20){
						pos.x=start.x;
						pos.y = maxY+100;
					}
					device.setLocation(new Point(pos.x,pos.y));
					pos.x=pos.x+AppConstant.DEFAULT_DEVICE_NAME_WIDTH+100;
					if(maxY<pos.y+AppConstant.DEFAULT_DEVICE_HEIGHT){
						maxY = pos.y+AppConstant.DEFAULT_DEVICE_HEIGHT;
					}
					System.out.println("new device/cpu "+name);
					parent.addChild(device);
					cache.put(name, device);
					parseJSON(json,root, device);
				}else if(base.equals("linker")){
					MLinker linker = new MLinker();
					linker.setName(name);
					linker.setClassName(clas);
					linker.setBaseType(base);
					linker.setBaseName(adjustDeviceName(root,name));
					if(pos.x+AppConstant.DEFAULT_DEVICE_NAME_WIDTH>start.x+size.width-20){
						pos.x=start.x;
						pos.y = maxY+100;
					}
					linker.setLocation(new Point(pos.x,pos.y));
					pos.x=pos.x+AppConstant.DEFAULT_DEVICE_NAME_WIDTH+100;
					if(maxY<pos.y+AppConstant.DEFAULT_DEVICE_HEIGHT){
						maxY = pos.y+AppConstant.DEFAULT_DEVICE_HEIGHT;
					}
					System.out.println("new linker "+name);
					parent.addChild(linker);
					cache.put(name, linker);
					parseJSON(json,root, linker);
				}
				/*switch(base){
				case "soc":
					MSOC soc = new MSOC();
					soc.setName(name);
					soc.setClassName(clas);
					soc.setBaseType(base);
					soc.setBaseName(adjustDeviceName(root,name));
					if(pos.x+AppConstant.DEFAULT_SOC_WIDTH>start.x+size.width-20){
						pos.x=start.x;
						pos.y = maxY+100;
					}
					soc.setLocation(new Point(pos.x,pos.y));
					pos.x=pos.x+AppConstant.DEFAULT_SOC_WIDTH+100;
					if(maxY<pos.y+AppConstant.DEFAULT_SOC_HEIGHT){
						maxY = pos.y+AppConstant.DEFAULT_SOC_HEIGHT;
					}
					System.out.println("new soc "+name);
					parent.addChild(soc);
					cache.put(name, soc);
					parseJSON(json,root, soc);
					
					break;
				case "cpu":
				case "device":
					MDevice device = new MDevice();
					device.setName(name);
					device.setClassName(clas);
					device.setBaseType(base);
					device.setBaseName(adjustDeviceName(root,name));
					if(pos.x+AppConstant.DEFAULT_DEVICE_NAME_WIDTH>start.x+size.width-20){
						pos.x=start.x;
						pos.y = maxY+100;
					}
					device.setLocation(new Point(pos.x,pos.y));
					pos.x=pos.x+AppConstant.DEFAULT_DEVICE_NAME_WIDTH+100;
					if(maxY<pos.y+AppConstant.DEFAULT_DEVICE_HEIGHT){
						maxY = pos.y+AppConstant.DEFAULT_DEVICE_HEIGHT;
					}
					System.out.println("new device/cpu "+name);
					parent.addChild(device);
					cache.put(name, device);
					parseJSON(json,root, device);
					break;
				case "linker":
					MLinker linker = new MLinker();
					linker.setName(name);
					linker.setClassName(clas);
					linker.setBaseType(base);
					linker.setBaseName(adjustDeviceName(root,name));
					if(pos.x+AppConstant.DEFAULT_DEVICE_NAME_WIDTH>start.x+size.width-20){
						pos.x=start.x;
						pos.y = maxY+100;
					}
					linker.setLocation(new Point(pos.x,pos.y));
					pos.x=pos.x+AppConstant.DEFAULT_DEVICE_NAME_WIDTH+100;
					if(maxY<pos.y+AppConstant.DEFAULT_DEVICE_HEIGHT){
						maxY = pos.y+AppConstant.DEFAULT_DEVICE_HEIGHT;
					}
					System.out.println("new linker "+name);
					parent.addChild(linker);
					cache.put(name, linker);
					parseJSON(json,root, linker);
					break;
				}*/
			}else{
				MNode node = (MNode) parent;
				if (value instanceof JSONArray){
					
					JSONArray array = (JSONArray)value;
					if(array.size()==0){
						return;
					}
					Object item = array.get(0);
					if(item instanceof JSONArray){//memory_space
						MDevice device = (MDevice) node;
						HashMap<String,MemorySpaceAttr> spaceInfo = device.getMemorySpaceInfo();
						for(int i=0;i<array.size();i++){
							MemorySpaceAttr spaceAttr = new MemorySpaceAttr();
							JSONArray space = array.getJSONArray(i);
							String devName = space.getString(2);
							String length = space.getString(3);
							String startAddress = space.getString(4);
							
							spaceAttr.setLength(length);
							spaceAttr.setStartAddress(startAddress);
							
							spaceInfo.put(devName, spaceAttr);
							
							Conn conn = new Conn();
							conn.source=devName;
							conn.sink=device.getName();
							conn.startAddress=startAddress;
							conn.length = length;
							connQueue.add(conn);
							
						}
						
					}else{
						String type = array.getString(0);
						String attrValue = array.getString(1);
						if(type.equals("iface")){
							Conn conn = new Conn();
							conn.source=node.getName();
							conn.sink=attrValue;	
							connQueue.add(conn);
						}else{
							Attribute attr = new Attribute();
							attr.setName(name);
							attr.setType(type);
							attr.setValue(attrValue);
							//node.getAttrList().add(attr);
						}
					}
				}
			}
		}
		
	}
	public static String adjustDeviceName(MRoot root,String name){
		Map<String,Integer> map = root.getNameMap();
		int pos = -1;
		for(int i=name.length()-1;i>0;i--){
			char a = name.charAt(i);
			if(a=='_'){
				pos=i;
				break;
			}
		}
		if (pos>1){
			String baseName = name.substring(0, pos);
			String sn = name.substring(pos+1);
			try{
				int isn = Integer.parseInt(sn);
				System.out.println(baseName);
				if(map.containsKey(baseName)){
					int cur=map.get(baseName);
					
						
						if(isn>cur){
							map.put(baseName, isn);
						}
					
				}else{
					map.put(baseName, isn);
				}
				return baseName;
			}catch(Exception e){
				e.printStackTrace();
			}
		}
		return name;
	}

}
